
/**
 
 1. 指针：指针就是地址
     指针变量：用来存储地址的变量
     
     通过指针变量可以间接的访问指针变量指向的另一个变量
 
 2. 声明一个指针量
     普通变量：格式 - 数据类型 变量名；int num；
     指针变量：格式 - 数据类型* 变量名；int * num；
     代表了一个指针变量，这个指针变量名字叫p1，这个指针变量的类型是int* 读int指针。
     *代表这个变量不是一个普通变量，是一个专门存储地址的指针变量
     这个p1指针只能存储地址
     指针变量只能存储和指针类型相同的地址
 
 3. 使用指针间接的
     格式： *指针变量名；代表这个指针指向的变量。
     int num = 10；
     int *p1 = &num；
     
     *p1 代表p1指针指向的变量，也就是num
     *p1完全等价于 num
     
     *p1=100；
     将100复制给p1指针指向的变量，也就是num变量
     
     可以通过*p1这种方式间接的给p1指向的变量赋值
 
 4. 野指针
     声明一个指针变量，如果没有为其初始化，那么这个时候指针变量中是有值的，垃圾值，随机数，这个时候，这个之后怎变量就有可能指向了1块随机的空间。
     这块空间：有可能无人使用，有可能别的程序在使用，有可能系统在用
     这个时候去访问指针指向的变量的时候，就会报错，BAD_ACCESS错误。
 
 5. NULL值
     NULL代表这个指针变量什么都不指 NULL==0
 
 6. 指针的类型原因：
     不管是什么类型的指针都占8个字节
 
     通过指针间接的操作指针指向的变量方式
     int num = 10；
     int *p1 = &num；
     p1指针变量中存储的是num变量的地址，也就是num变量的低字节的地址
     通过这个p1指针其实只能找到这个地址的字节
     这个时候，通过p1指针找到这个字节 操作的时候，是操作多个字节空间呢？操作多少个字节是根据指针类型决定的
     指针变量的类型决定了 通过这个指针找到这个字节以后 连续操作多少个字节空间
     
     指针是int* 那么久连续操作4
     指针是float* 那么久连续操作4
     指针是double* 那么久连续操作8
     指针是char* 那么久连续操作1
     
     指针变量一定要指向和类型相同的普通变量

 
 
 7. 多级指针：
     一级指针变量中存储的是1个普通变量的地址，二级指针变量中存储的是1个一级指针变量的地址以此类推。
     二级指针：
     声明
     数据类型** 指针名；
     
     初始化：使用&拿到对应的指针变量的地址赋值给指针变量就可以了
 
 8. 指针和整数加减运算：
     并不是字节数加1，而是在这个指针地址的基础之上+1个单位变量占用的字节数
 
 9. 指针与数组：
     遍历数组：
     方式1
     int arr[] = {10, 20, 30, 40, 50};
     for (int i = 0; i < 5; i++) {
        printf(“%d\n”, *(arr + 1));
     }
     方式2
     int arr[] = {10, 20, 30, 40, 50};
     int *p = arr;
     for (int i = 0; i < 5; i++) {
        printf("%d\n", *(p++));
     }
 
 10. 数组作为函数的参数
     直接写指向数组的指针
     void test(int* arr, int len) { }
 11. 数组索引的本质
     1）指针变量后面可以使用中括号，在中括号中写上下标来访问数据
     2）p[n]；前提  p是一个指针变量
     完全等价于 *(p+1);
     3）只要是指针都可以使用中括号下标，来访问指针指向的变量
 
 12. 存储只指针的数组
     数据类型* 数组名[数组的长度]；
     int *arr[3];
 
 13. 指针加减法运算
     能相减，结果是一个long类型
     两个指针指向的变量之间相差多少个单位变量
     绝大多数情况下，我们用在怕暖两个元素之间相差多少个元素。
     参与减法运算的两个指针不知想同一个数组，结果就有问题：
     先求出两个指针的差 / 每一个指针指向变量对应的普通变量占用的字节数
     
     指针之间不能做加法运算
 
 14. 指针和指针的比较运算
 */

/**
 1. 使用字符指针来存储字符串数据
	char *name = “jack”;
 2. 内存中的五大区域：
 不管是哪一个区域，都是用来存储数据的，方便管理
     a. 栈
        存储 局部变量
     b. 堆
        允许程序员手动的从堆申请空间来使用
     c. BSS段
        存储 未初始化的全局变量和静态变量。
        在程序运行的最开始的时候，这个全局变量是没有初始化的，存储在BSS段
     d. 数据段/常量
        存储 已经初始化的全局变量和静态变量还有常量数据
     e. 代码段
        存储 程序的代码/指令
 
 3. 存储字符串两种方式区别：
     char name[] = “jack”;
     char *name = “jack”;
     区别：
         1）都是局部变量的时候
         char name1[] = “jack”;
         char *name2 = “rose”;
             a  name1字符数组是申请在栈区的，字符串你的每一个字符存储在这个字符数组的每一个元素中
             b  name2是一个局部的指针变量，name2 这个指针变量是声明在栈区的，这个时候，字符串数据是存储在常亮区中的，字符串数据就是以字符数组的形式存储在常量区。name2指针变量中，存储的是“rose”这个字符串在常量区的地址。
         
         2）全局变量的时候
             a  name1 数组是存储在常量区的，字符串的每一个字符是存储在这个数组中的每一个元素中
             b  name2 指针也是存储在常量区的，字符串也是以字符数组的形式存储在常量区，name2 指针中存储的是 “rose”这个字符串在常量区的地址。
         
         两种方式的区别：
         （1）. 在内存中存储肚饿结构是不同的
             a  以字符数组存储：无论如何是一个字符数组，然后字符数组的每一个字符存储在数组的元素之中
             b  以字符指针存储：无论如何首先1个字符指针变量，字符数组是以字符数组的形式存储在常量区的。
         （2）.
             a. 以字符数组村胡扯的字符串数据，可以修改字符数组的元素
             以字符数组村胡扯的字符串数据，不管是全局的还是局部的，都可以使用下标去修改字符数组中的每一个元素。
             b. 以字符指针的形式存储字符串数据，字符指针指向的字符串数据是无法修改的
             以字符指针的形式存储字符串数据，不管是全局的还是局部的，都不能通过指针修改指向的字符串数据
             可变不可变
 */

/**
 fputs()函数
     作用：将字符串数据输出到指定的流当中
     流：标准输出流—>控制台
        文件流 —> 磁盘上的文件
     格式：
         1. 输出到标准输出流
             fputs（要输出的字符串，指定的流）
         2. 将字符串存储到文件里面
             a）要先声明1个文件指针，指向磁盘上的文件
             FILE* pFile = fopen(“要指向的文件路径”, “操作文件的模式, 你要对文件做什么操作”);
             操作方式：
                 w  write  写数据
                 r  read   读数据
                 a  append 追加数据
             b）使用 fputs函数将字符串写入到指定文件流中。
                 fputs(字符串, 文件指针)
             c）使用fclose将这个文件关闭
        注意：
         1. 当操作模式是“w”的时候，如果文件不存在，就会创建这个文件，文件存在，就将原来的文件替换掉
         2. 当操作模式是“a”，如果文件不存在就创建这个文件，文件存在，就直接追加
 
 fgets()函数
 作用：从指定流中读取字符串，这个流可以使我们的标准输入流 —> 控制台，也可以是文件流
     1）使用fgets()函数从标准输入流中读取数据
     scanf()函数缺点
        不安全，输入空格会被认为结束
     get() 函数缺点
         不安全
     fgets()函数优点
         安全，空格也会一并接收
     
     语法：
     fgets(准备存储到那个数组中，尊卑接收的最长长度，指定流)
     stdin：标准输入流，键盘流，控制台
     注意：
         1）输入的长度大于等于第二个参数，只会接收前面n-1个字符，最后一个自动是“\0”
         2）输入的字符串长度刚好等于n-1，完美
         3）输入长度小于 n-1，最后一个是‘\n’然后后面是‘\0’
     2）使用fgets()函数读取文件的内容
         a）创建读取文件的文件流
         b）准备字符数组，来存储数据
         c）使用fgets函数读取
         d）使用fclose关闭文件流

 
 */

#include <stdio.h>
#include <string.h>


void fputsFile() {
    FILE *pFile = fopen("/Users/zhouchenglong/Desktop/abc.txt", "a");
    char *string = "今天天气好haoa ";
    fputs(string, pFile);
}

void fgetsStdin() {
    printf("请输入：\n");
    char input[5];
    fgets(input, 5, stdin);
    
    size_t len = strlen(input);
    if (input[len- 1] == '\n') {
        input[len- 1] = '\0';
    }
    
    printf("%s\n", input);
}

void fgetsFile() {
    // 文件路径下面要有文件存在
    FILE *pFile = fopen("/Users/zhouchenglong/Desktop/abc.txt", "r");
    char input[50];
    fgets(input, 50, pFile);
    fclose(pFile);
    printf("读出来的内容是：%s\n", input);
}

int main(int argc, const char * argv[]) {
    // insert code here...
//    int arr[] = {10, 20, 30, 40, 50};
//    int *p = arr;
//    for (int i = 0; i < 5; i++) {
//        printf("%d\n", *(p++));
//    }
    
//    fputsFile();
    
    fgetsFile();
    
    return 0;
}
